/* =================================================
 * Package:			dk.iha.toksEditor
 * File:			DataBaseConnection.java
 * Description:		This is the class for which is
 * 					responsible for all the
 * 					communication to the server
 * 
 * Responsible
 * =================================================
 * Name:			Bjarke Jensen
 * Study number:	09676
 */

package dk.iha.toksEditor;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Date;
import java.util.GregorianCalendar;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.util.Base64;
import android.util.Log;




public class DataBaseConnection {
	private int defaultConnectionTimeout = 50000;
	private String baseURI = "http://130.225.184.205:8082/pfpas-mobile/rest/";
	
	private String logOnURI = "common/login";
	private String logOnSettings = "settings/";
	
	private String patientInformation = "patientinformation/patients/";
	private String isAdmitted = "admittance/CPR/ID";
	
	private String favorites = "favorites/";
	
	private String addTOKS = "resultsFIXME/EWS/";
	private String getTOKSHistory = "resultsFIXME/history/EWS/CPR/?rows=";
	private String prescription = "resultsFIXME/prescription/EWS/";
	
	private User mUser;
	
	
	/**
	 * Constructor of DataBaseConnection class.
	 * Used with User as parameter.
	 *
	 * @param  user  The user used for database identification.
	 */
	public DataBaseConnection(User user) {
		mUser = user;
	}
	
	/**
	 * Generates the authorization key used in the database.
	 *
	 * @return   {@link String}   Base64-authkey used in header of http-GET/POST/DELETE/PUT
	 */
	private String getAuthorizationString() 
	{
        final String auth = mUser.getUserName() + ":" + mUser.getPassword();
        String encodedAuth = Base64.encodeToString(auth.getBytes(), Base64.DEFAULT);
        return "Basic " + encodedAuth.trim();
	}
		
	/**
	 * Returns an object of the custom class {@link RequestResponse}.
	 * Uses GET-HTTP.
	 *
	 * @param  URI  An absolute URL to the database to GET from. {@link String}
	 * @return      {@link RequestResponse} A RequestResponse containing HTTP response code and HTTP-body response.
	 */
	private RequestResponse getRequest(String URI) 
	{
	
	    HttpGet request = new HttpGet(URI);
		RequestResponse ret = new RequestResponse(-1);
		   
		request.addHeader("Authorization", getAuthorizationString());
		   
		HttpParams httpParameters = new BasicHttpParams();
		HttpConnectionParams.setConnectionTimeout(httpParameters, defaultConnectionTimeout );
		HttpConnectionParams.setSoTimeout(httpParameters, defaultConnectionTimeout);
		HttpClient client = new DefaultHttpClient(httpParameters);
		   
		try {
			HttpResponse response = client.execute(request);
			HttpEntity entity = response.getEntity();
			ret.setStatusCode(response.getStatusLine().getStatusCode());
			  
			if(entity != null) 
			{
				ret.setContent(new BufferedReader(new InputStreamReader(entity.getContent())));
			}
		}
		catch (IOException e) 
		{
			Log.e("TAG", e.toString());
			return RequestResponse.error();
		}
		return ret;
	}
	
	/**
	 * Returns an object of the custom class RequestResponse (Contains HTTP response code 
	 * (eg. 404) and the response in BufferedReader).
	 * Uses POST-HTTP.
	 *
	 * @param  URI  an absolute URL to the database to POST to.
	 * @param  message Message to POST to database.
	 * @return       {@link RequestResponse} A RequestResponse containing HTTP response code and HTTP-body response.
	 */
	private RequestResponse postRequest(String URI, String message)
	{
		HttpPost request = new HttpPost(URI);
		try
		{
		 request.setEntity(new StringEntity(message));
		}
		catch (Exception e) 
		{
			e.printStackTrace();
		}
		request.setHeader("Content-type", "application/json");
		
		request.addHeader("Authorization", getAuthorizationString());
		 
		RequestResponse ret = new RequestResponse(-1);
		   
		HttpParams httpParameters = new BasicHttpParams();
		HttpConnectionParams.setConnectionTimeout(httpParameters, defaultConnectionTimeout );
		HttpConnectionParams.setSoTimeout(httpParameters, defaultConnectionTimeout);
		HttpClient client = new DefaultHttpClient(httpParameters);
		   
		try {
			HttpResponse response = client.execute(request);
			HttpEntity entity = response.getEntity();
			ret.setStatusCode(response.getStatusLine().getStatusCode());
			  
			if(entity != null) 
			{
				ret.setContent(new BufferedReader(new InputStreamReader(entity.getContent())));
			}
		}
		catch (IOException e) 
		{
			Log.e("TAG", e.toString());
			return RequestResponse.error();
		}
		return ret;
	}
	
	/**
	 * Returns an object of the custom class RequestResponse (Contains HTTP response code 
	 * (eg. 404) and the response in BufferedReader).
	 * Uses DELETE-HTTP.
	 *
	 * @param  URI  an absolute URL to the database to DELETE from
	 * @return       {@link RequestResponse} A RequestResponse containing HTTP response code and HTTP-body response.
	 */	
	private RequestResponse deleteRequest(String URI) 
	{
	
	    HttpDelete request = new HttpDelete(URI);
		RequestResponse ret = new RequestResponse(-1);
		   
		request.addHeader("Authorization", getAuthorizationString());
		   
		HttpParams httpParameters = new BasicHttpParams();
		HttpConnectionParams.setConnectionTimeout(httpParameters, defaultConnectionTimeout );
		HttpConnectionParams.setSoTimeout(httpParameters, defaultConnectionTimeout);
		HttpClient client = new DefaultHttpClient(httpParameters);
		   
		try {
			HttpResponse response = client.execute(request);
			HttpEntity entity = response.getEntity();
			ret.setStatusCode(response.getStatusLine().getStatusCode());
			  
			if(entity != null) 
			{
				ret.setContent(new BufferedReader(new InputStreamReader(entity.getContent())));
			}
		}
		catch (IOException e) 
		{
			Log.e("TAG", e.toString());
			return RequestResponse.error();
		}
		return ret;
	}
	
	/**
	 * Returns an object of the custom class RequestResponse (Contains HTTP response code 
	 * (eg. 404) and the response in BufferedReader).
	 * Uses PUT-HTTP.
	 *
	 * @param  URI  an absolute URL to the database to POST to.
	 * @param  message Message to PUT to database.
	 * @return       {@link RequestResponse} A RequestResponse containing HTTP response code and HTTP-body response.
	 */
	private RequestResponse putRequest(String URI, String message)
	{
		HttpPut request = new HttpPut(URI);
		try
		{
		 request.setEntity(new StringEntity(message));
		}
		catch (Exception e) 
		{
			e.printStackTrace();
		}
		request.setHeader("Content-type", "application/json");
		
		request.addHeader("Authorization", getAuthorizationString());
		 
		RequestResponse ret = new RequestResponse(-1);
		   
		HttpParams httpParameters = new BasicHttpParams();
		HttpConnectionParams.setConnectionTimeout(httpParameters, defaultConnectionTimeout );
		HttpConnectionParams.setSoTimeout(httpParameters, defaultConnectionTimeout);
		HttpClient client = new DefaultHttpClient(httpParameters);
		   
		try {
			HttpResponse response = client.execute(request);
			HttpEntity entity = response.getEntity();
			ret.setStatusCode(response.getStatusLine().getStatusCode());
			  
			if(entity != null) 
			{
				ret.setContent(new BufferedReader(new InputStreamReader(entity.getContent())));
			}
		}
		catch (IOException e) 
		{
			Log.e("TAG", e.toString());
			return RequestResponse.error();
		}
		return ret;
	}
		
	
	/**
	 * Returns a bool whether the User used in the constructor is OK or not
	 *
	 * @return      {@link Boolean} True if user is ok. False if user is not good.
	 */
	public Boolean LogInOK()
	{
		RequestResponse r = getRequest(baseURI+logOnURI);
		if(r.getStatusCode() == 200)
			return true;
		else
			return false;
	}
	
	
	/**
	 * Returns a String with the user-type of the current user.
	 * @return      {@link String} A String containing DOCTOR or NURSE.
	 */
	public String getUserType()
	{
		RequestResponse r = getRequest(baseURI+logOnSettings+mUser.getUserName());
		if(r.getStatusCode() == 200)
		{
			BufferedReader f = r.getContent();
			JSON j = new JSON();
			String h = "";
			try
			{
				h = (j.unJSON(f).getJSONObject(0)).optString("profile");
			}
			catch (JSONException e)
			{
				e.printStackTrace();
				return null;
			}	
			return h;
		}
		return null;
	}
	
	/**
	 * Returns a Patient containing Name and CPR.
	 *
	 * @param	CPR	CPR of the patient wanted to get data of.
	 * @return 	{@link Patient}	A Patient containing Name and CPR.
	 */	
	public Patient patientInformation(String CPR)
	{
		if(patientExist(CPR))
		{
			RequestResponse r = getRequest(baseURI+patientInformation+CPR);
			
			JSONArray ar = JSON.unJSON(r.getContent());
			String cpr = "", name  = "";
			try
			{
				cpr = ar.getJSONObject(0).getString("cpr");
				name = ar.getJSONObject(0).getString("name");
			}
			catch (JSONException e)
			{
				e.printStackTrace();
				return null;
			}	
			return new Patient(cpr,name);
		}
		else
			return null;
	}
	
	private Boolean patientExist(String CPR)
	{
		RequestResponse r = getRequest(baseURI+(isAdmitted.replace("CPR", CPR)));
		if(r.getStatusCode() != 200)
			return false;
		else
			return true;
	}
	
	/**
	 * Returns a ArrayList of all the patients in the favoritelist.
	 *
	 * @return  ArrayList of all patients.
	 */		
	public Boolean listFavorites(ArrayList<Patient> patients)
	{
		
		RequestResponse r = getRequest(baseURI+favorites);
		if(r.getStatusCode() == 200)
		{
			JSONArray ar = JSON.unJSON(r.getContent());
			for (int i = 0; i < ar.length();i++) {
				try
				{
					Patient p = new Patient(
							ar.getJSONObject(i).optString("cpr"), 
							ar.getJSONObject(i).optString("name"),
							ar.getJSONObject(i).optString("note"));
					patients.add(p);
				}
				catch (Exception e) {
					e.printStackTrace();
					return false;
				}
			}
			return true;
		}
		return false;
	}
	
	/**
	 * Adds a patient to favoriteslist.
	 *
	 * @param	patient	The patient to add to the favoriteList.
	 * @return	returns whether it completed successfully or not.
	 */		
	public boolean addToFavorites(Patient patient)
	{
		RequestResponse r = postRequest(
				baseURI+favorites+patient.getCPR(),
				"{\"note\":\""+patient.getNote()+"\", \"color\":\"WHITE\"}");
		if(r.getStatusCode() != 200)
			return false;
		return true;
		
	}
	
	/**
	 * Deletes a patient from the favoriteslist.
	 *
	 * @param	patient	The patient to remove from favoriteslist.
	 * @return	Returns if it went well or not.
	 */	
	public boolean deleteFromFavorites(Patient patient)
	{
		RequestResponse r = deleteRequest(baseURI+favorites+patient.getCPR());
		if(r.getStatusCode() != 200)
			return false;
		return true;
	}
	
	/**
	 * Updates note of a patient in the favoriteslist.
	 *
	 * @param	patient	The patient to update note of in favoriteslist. 
	 */	
	public Boolean updateNoteFavoritePatient(Patient patient)
	{
		RequestResponse r = putRequest(baseURI+favorites+patient.getCPR(), "{\"note\": \""+patient.getNote()+"\",\"color\": \"WHITE\"}");
		if(r.getStatusCode() != 200)
			return false;
		else
			return true;
	}
	
	/**
	 * A List of all (limited by maxResults-parameter) the TOKS-values for a patient
	 *
	 * @param	patient	The Patient to get the TOKS of.
	 * @param	maxReults	Limits how many results to get.	
	 * @return  ArrayList	A list of TOKS for the selected patient.
	 */	
	public ArrayList<TOKS> getTOKSHistory(Patient patient, Integer maxReults)
	{				
		ArrayList<TOKS> toks = new ArrayList<TOKS>();
		RequestResponse r = getRequest(baseURI+getTOKSHistory.replace("CPR", patient.getCPR())+maxReults);
		if(r.getStatusCode() == 200)
		{
			JSONArray ar2 = JSON.unJSON(r.getContent());
			
			for (int i = 0; i < ar2.length();i++) {
				try
				{
					TOKS t = new TOKS();
					//SimpleDateFormat sf = new SimpleDateFormat("MMM dd, yyyy h:mm:ss aa"); //Jun 4, 2012 8:42:00 AM
					Date d = undate(ar2.getJSONObject(i).optString("creationTimestamp"));
					t.setDate(d);
					
					
					JSONObject ar = ar2.getJSONObject(i).optJSONObject("dto");
					
					t.setRespirationFrequency(ar.optInt("respirationFrequency")); 
					t.setBloodPressureSystolic(ar.optInt("bloodPressureSystolic"));
					t.setHeartRate(ar.optInt("heartRate"));
					t.setTemperature(ar.optDouble("temperature"));
					
					t.setSaturation(ar.optInt("saturation"));
					t.setBloodPressureDiastolic(ar.optInt("bloodPressureDiastolic"));
					t.setConsciousness(ar.optString("consciousness"));
					t.setOxygenLitersPerMinute(ar.optDouble("oxygenLitersPerMinute"));
					t.setDecisionAlgorithm(ar.optString("decisionAlgorithm"));
					t.setTotalScore(ar.optInt("totalScore"));
					
					
					toks.add(t);
				}
				catch (Exception e) {
					e.printStackTrace();
					return null;
				}
			}
			
			return toks;
		}
		return null;
	}

	/**
	 * Adds a new TOKS to a patient.
	 *
	 * @param	patient {@link Patient}	The patient to add the TOKS to.
	 * @throws Exception 
	 */	
	public void addTOKS(Patient patient) throws Exception {
		RequestResponse r = postRequest(baseURI+addTOKS+patient.getCPR(),patient.getTOKS().toString());
		if(r.getStatusCode() != 200)
			throw new Exception();
	}
	
	public Boolean isPatientFavorite(Patient patient)
	{
		RequestResponse r = getRequest(baseURI+favorites+patient.getCPR());
		if(r.getStatusCode() != 200)
			return false;
		else
			return true;
	}
	
	public String getPatientNote(Patient patient)
	{
		RequestResponse r = getRequest(baseURI+favorites+patient.getCPR());
		if(r.getStatusCode() == 200)
		{
			try
			{				
				JSONArray ar = JSON.unJSON(r.getContent()); 
				return ar.getJSONObject(0).optString("note");
			}
			catch (Exception e) {
				return null;
			}
		}
		return null;
	}
	
	
	/**
	 * Get prescribed TOKS for a patient.
	 *
	 * @param	patient {@link Patient}	The patient to get prescribed TOKS from.
	 */
	public Integer prescripedTOKS(Patient patient)
	{
		RequestResponse r = getRequest(baseURI+prescription+patient.getCPR());
		Integer ret = -1;
		if(r.getStatusCode() != 200)
			return null;
		JSONArray ar = JSON.unJSON(r.getContent());
		
		try{
			ret = ar.getJSONObject(0).optInt("allowableEWS");
		}
		catch (Exception e) {
			return null;
		}
		return ret;
	}	
	
	private Date undate(String sDate)
	{
		int year = 0,month = 0,day = 0,hour = 0,minute = 0,second = 0;
		StringBuilder sb = new StringBuilder(sDate);
		
		int commaPos = sb.indexOf(",");
		
		String monthdate = sb.substring(0,commaPos);
		String sMonth = monthdate.substring(0,monthdate.indexOf(" "));		
		if(sMonth.contains("Jan"))
			month = 0;
		else if(sMonth.contains("Feb"))
			month = 1;
		else if(sMonth.contains("Mar"))
			month = 2;
		else if(sMonth.contains("Apr"))
			month = 3;
		else if(sMonth.contains("May"))
			month = 4;
		else if(sMonth.contains("Jun"))
			month = 5;
		else if(sMonth.contains("Jul"))
			month = 6;
		else if(sMonth.contains("Aug"))
			month = 7;
		else if(sMonth.contains("Sep"))
			month = 8;
		else if(sMonth.contains("Oct"))
			month = 9;
		else if(sMonth.contains("Nov"))
			month = 10;
		else if(sMonth.contains("Dec"))
			month = 11;
		day =Integer.parseInt(monthdate.substring(monthdate.indexOf(" ")+1,monthdate.length()));		
		
		year = Integer.parseInt(sb.substring(commaPos+2,commaPos+6));
				
		String time= sb.substring(commaPos+7,sb.length());
		String[] stamp = time.split(":");
		hour = Integer.parseInt(stamp[0]);
		if(stamp[2].contains("PM"))
			hour +=12;
		minute = Integer.parseInt(stamp[1]);
		
		
		GregorianCalendar d = new GregorianCalendar(year,month,day,hour,minute);
		
		return new Date(d.getTimeInMillis());
	}
}
